package com.azier.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.util.Map;
import java.util.Properties;

/**
 * <p>
 * User: 金建强(ptma@163.com)
 * </p>
 * <p>
 * Date: 2015-11-11 17:29.
 * </p>
 */
public final class PropertiesUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesUtil.class);

    private PropertiesUtil(){

    }

    /**
     * 从文件创建 properties.
     *
     * @param fileName properties 文件名
     */
    public static Properties createFromFile(String fileName) throws IOException {
        return createFromFile(new File(fileName));
    }

    /**
     * 从文件创建 properties.
     *
     * @param file properties File对象
     */
    public static Properties createFromFile(File file) throws IOException {
        Properties prop = new Properties();
        loadFromFile(prop, file);
        return prop;
    }

    /**
     * 从文件载入 properties. 合并到 properties 中.
     *
     * @param p 目标 properties
     * @param fileName 待合并的 properties 文件名
     */
    public static void loadFromFile(Properties p, String fileName) throws IOException {
        loadFromFile(p, new File(fileName));
    }

    /**
     * 从文件载入 properties. 合并到 properties 中.
     *
     * @param p 目标 properties
     * @param file 待合并的 properties 文件
     */
    public static void loadFromFile(Properties p, File file) throws IOException {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            p.load(fis);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    LOGGER.trace(e.getMessage(), e);
                }
            }
        }
    }

    /**
     * 写入 properties 到一个文件.
     *
     * @param p 待写入的 properties
     * @param fileName 目标文件文件名
     */
    public static void writeToFile(Properties p, String fileName) throws IOException {
        writeToFile(p, new File(fileName), null);
    }

    /**
     * 写入 properties 到一个文件.
     *
     * @param p 待写入的 properties
     * @param fileName 目标文件名
     * @param header 可选, 注释头
     */
    public static void writeToFile(Properties p, String fileName, String header) throws IOException {
        writeToFile(p, new File(fileName), header);
    }

    /**
     * 写入 properties 到一个文件.
     *
     * @param p 待写入的 properties
     * @param file 目标文件
     */
    public static void writeToFile(Properties p, File file) throws IOException {
        writeToFile(p, file, null);
    }

    /**
     * 写入 properties 到一个文件.
     *
     * @param p 待写入的 properties
     * @param file 目标文件
     * @param header 可选, 注释头
     */
    public static void writeToFile(Properties p, File file, String header) throws IOException {
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            p.store(fos, header);
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    LOGGER.trace(e.getMessage(), e);
                }
            }
        }
    }

    // ---------------------------------------------------------------- to/from string

    /**
     * 从字符串创建 Properties.
     */
    public static Properties createFromString(String data) throws IOException {
        Properties p = new Properties();
        loadFromString(p, data);
        return p;
    }

    /**
     * 从字符串载入内容到已有的 Properties.
     */
    public static void loadFromString(Properties p, String data) throws IOException {
        ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes("ISO_8859_1"));
        try {
            p.load(is);
        } finally {
            is.close();
        }
    }

    /**
     * 从已有的 Properties 中提取指定前缀的属性子集到一个新的 Properties. 新的子集中的键名可选择是否剥离掉前缀.
     *
     * @param p 源 properties, from which new object will be created
     * @param prefix 键名前缀
     * @return subset 子集 properties
     */
    public static Properties subset(Properties p, String prefix, boolean stripPrefix) {
        if (StringUtil.isBlank(prefix)) {
            return p;
        }
        String thePrefix = prefix;
        if (!thePrefix.endsWith(".")) {
            thePrefix += ".";
        }
        Properties result = new Properties();
        int baseLen = thePrefix.length();
        for (Object o : p.keySet()) {
            String key = (String) o;
            if (key.startsWith(thePrefix)) {
                result.setProperty(stripPrefix ? key.substring(baseLen) : key, p.getProperty(key));
            }
        }
        return result;
    }

    /**
     * 从 map 获取指定键对应的值. 如果键不存在或值不是 String, 返回<code>null</code>. 类似于 <code>Property.getProperty</code>, 只不过用于 map 上.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static String getProperty(Map map, String key) {
        return getProperty(map, key, null);
    }

    /**
     * 从 map 获取指定键对应的值
     *
     * @see #getProperty(Map, String)
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static String getProperty(Map map, String key, String defaultValue) {
        Object val = map.get(key);
        return (val instanceof String) ? (String) val : defaultValue;
    }
}
